package com.ease.integration.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import com.ease.common.util.Detect;

public class CommonsNetFtpClient extends FtpClient {

	private FTPClient ftpClient;

	public boolean connect() throws RuntimeException {
		try {
			// ftpClient.setControlEncoding("GBK");
			ftpClient.setControlEncoding("UTF-8");
			ftpClient.connect(host, port);

			ftpClient.login(username, password);

			ftpClient.enterLocalPassiveMode();
			int returnCode = ftpClient.pasv();
			returnCode = ftpClient.getReplyCode();

			ftpClient.setDataTimeout(10000);
			if (!FTPReply.isPositiveCompletion(returnCode)) {
				// if(log.isDebugEnabled()){
				// log.debug("FTP server refused connection.returnCode=" + returnCode);
				// }
				throw new Exception("FTP server refused connection.returnCode=" + returnCode);
			}
			// if(log.isDebugEnabled()){
			// log.debug("connected to FTP server. ip=" + serverIp);
			// }

			return true;
		} catch (Exception e) {
			throw new RuntimeException("host=" + host + ", port=" + port + ", username=" + username + ", password=xxxxxx", e);
		}
	}

	public boolean disconnect() {
		try {
			if (null != ftpClient) {
				ftpClient.logout();
				ftpClient.disconnect();
			}
			return true;
		} catch (IOException e) {
			// Caused by: java.io.IOException: Connection is not open
			// at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:474)
			// at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:556)
			// at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:605)
			// at org.apache.commons.net.ftp.FTP.quit(FTP.java:813)
			// at org.apache.commons.net.ftp.FTPClient.logout(FTPClient.java:1045)
			// at com.ease.integration.ftp.CommonsNetFtpClient.disconnect(CommonsNetFtpClient.java:52)
			// ... 26 more

			// throw new RuntimeException(e);
		}
		return false;
	}

	public void changeWorkingDirectoryIfNecessary(String remoteDirectory) {
		if (Detect.notEmpty(remoteDirectory)) {
			try {
				ftpClient.changeWorkingDirectory(remoteDirectory);
			} catch (IOException e) {
				throw new RuntimeException("remoteDirectory" + remoteDirectory, e);
			}
		}
	}

	public boolean uploadFile(String remoteDirectory, File file) throws RuntimeException {

		if (null != file && !file.isDirectory()) {
			changeWorkingDirectoryIfNecessary(remoteDirectory);

			FileInputStream input = null;
			try {
				input = new FileInputStream(file);

				ftpClient.storeFile(file.getName(), input);
				return true;
			} catch (FileNotFoundException e) {
				throw new RuntimeException(e);
			} catch (IOException e) {
				throw new RuntimeException(e);
			} finally {
				if (null != input) {
					try {
						input.close();
					} catch (IOException e) {
						throw new RuntimeException(e);
					}
				}
			}

		}
		return false;
	}

	public boolean uploadDirectory(String remoteDirectory, File file) throws RuntimeException {
		if (null != file && file.isDirectory()) {
			changeWorkingDirectoryIfNecessary(remoteDirectory);
			String directory = file.getName();
			try {
				ftpClient.makeDirectory(directory);
				changeWorkingDirectoryIfNecessary(directory);

				String[] fileNames = file.list();
				for (String fileName : fileNames) {
					File subfile = new File(file.getPath() + File.separatorChar + fileName);
					if (subfile.isDirectory()) {
						uploadDirectory(remoteDirectory + File.separatorChar + directory, subfile);
						ftpClient.changeToParentDirectory();
					} else {
						uploadFile(remoteDirectory + File.separatorChar + directory, subfile);
					}
				}
				return true;
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
		return false;
	}

	public boolean downloadDirectory(String remoteDirectory) throws RuntimeException {
		// TODO
		return false;
	}

	public boolean downloadFile(String remoteDirectory, String remoteFileName, String localDirectory, String localFileName) throws RuntimeException {
		OutputStream outputStream = null;
		try {
			ftpClient.changeWorkingDirectory(remoteDirectory);

			FTPFile[] FTPFiles = ftpClient.listFiles();

			for (FTPFile ftpFile : FTPFiles) {
				if (ftpFile.getName().equals(remoteFileName)) {
					outputStream = new FileOutputStream(filePath(localDirectory, localFileName));
					ftpClient.retrieveFile(remoteFileName, outputStream);
					return true;
				}
			}

			return false;
		} catch (FileNotFoundException e) {
			if (null != outputStream) {
				try {
					outputStream.close();
				} catch (IOException e1) {
					throw new RuntimeException(e);
				}
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return false;
	}

	public boolean hasFile(String remoteDirectory, String fileName) throws RuntimeException {
		try {
			String[] names = ftpClient.listNames(remoteDirectory);
			return Detect.contains(fileName, names);
		} catch (IOException e) {
			throw new RuntimeException("remoteDirectory=" + remoteDirectory + ", fileName=" + fileName, e);
		}
	}

	public boolean remove(String remoteDirectory, String fileName) throws RuntimeException {
		try {
			return ftpClient.deleteFile(filePath(remoteDirectory, fileName));
		} catch (IOException e) {
			throw new RuntimeException("remoteDirectory=" + remoteDirectory + ", fileName=" + fileName, e);
		}
	}

	public static String filePath(String directory, String fileName) {
		String filePath = directory + "/" + fileName;
		return filePath.replaceAll("//", "/");

	}

	/**
	 * @return the ftpClient
	 */
	public FTPClient getFtpClient() {
		return ftpClient;
	}

	/**
	 * @param ftpClient
	 *            the ftpClient to set
	 */
	public void setFtpClient(FTPClient ftpClient) {
		this.ftpClient = ftpClient;
	}

}
